package repository

import (
	"context"
	"fmt"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)

type genericRepository struct {
	entityType reflect.Type    // 实体类型信息
	primaryKey string          // 主键字段名
	indexes    map[string]bool // 索引字段名集合

	db          DBProvider    // 底层数据库提供者
	cache       CacheProvider // 缓存提供者
	cacheConfig CacheConfig   // 缓存配置

	mu sync.RWMutex // 保护类型信息
}

// NewRepository 创建新的Repository实例
func NewRepository(
	entityType interface{},
	db DBProvider,
	cacheConfig CacheConfig,
) (Repository, error) {
	// 获取类型信息
	t := reflect.TypeOf(entityType)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 解析主键和索引
	primaryKey, indexes := parseTags(t)

	// 初始化缓存
	var cache CacheProvider
	if cacheConfig.Enabled {
		if cacheConfig.RedisConfig != nil {
			rdb := redis.NewClient(&redis.Options{
				Addr:     cacheConfig.RedisConfig.Addr,
				Password: cacheConfig.RedisConfig.Password,
				DB:       cacheConfig.RedisConfig.DB,
			})
			cache = NewRedisCacheProvider(rdb, cacheConfig.TTL)
		} else {
			cache = NewMemoryCacheProvider(cacheConfig.MaxItems, cacheConfig.TTL)
		}
	}

	return &genericRepository{
		entityType:  t,
		primaryKey:  primaryKey,
		indexes:     indexes,
		db:          db,
		cache:       cache,
		cacheConfig: cacheConfig,
	}, nil
}

// parseTags 解析结构体标签
func parseTags(entityType reflect.Type) (string, map[string]bool) {
	primaryKey := ""
	indexes := make(map[string]bool)

	for i := 0; i < entityType.NumField(); i++ {
		field := entityType.Field(i)
		tag := field.Tag.Get("repo")

		if tag == "" {
			continue
		}

		tags := strings.Split(tag, ",")
		for _, t := range tags {
			switch t {
			case PrimaryKeyTag:
				primaryKey = field.Name
			case IndexTag:
				indexes[field.Name] = true
			}
		}
	}

	return primaryKey, indexes
}

// Save 保存实体
func (r *genericRepository) Save(ctx context.Context, entity interface{}) error {
	if err := r.validateEntityType(entity); err != nil {
		return err
	}

	// 1. 保存到数据库
	if err := r.db.Save(ctx, entity); err != nil {
		return err
	}

	// 2. 更新缓存
	if r.cache != nil {
		id, err := r.getIDValue(entity)
		if err != nil {
			return err
		}

		if err := r.cache.Set(ctx, r.cacheKey(id), entity); err != nil {
			return err
		}

		// 更新索引缓存
		if err := r.updateIndexes(ctx, entity); err != nil {
			return err
		}
	}

	return nil
}

// FindByID 通过ID查找
func (r *genericRepository) FindByID(ctx context.Context, id interface{}) (interface{}, error) {
	// 1. 尝试从缓存获取
	if r.cache != nil {
		if entity, err := r.cache.Get(ctx, r.cacheKey(id)); err == nil && entity != nil {
			return entity, nil
		}
	}

	// 2. 从数据库获取
	entity, err := r.db.FindByID(ctx, id)
	if err != nil {
		return nil, err
	}

	// 3. 填充缓存
	if r.cache != nil && entity != nil {
		if err := r.cache.Set(ctx, r.cacheKey(id), entity); err != nil {
			return nil, err
		}
	}

	return entity, nil
}

// FindByIndex 通过索引查找
func (r *genericRepository) FindByIndex(ctx context.Context, indexName string, indexValue interface{}) ([]interface{}, error) {
	if !r.indexes[indexName] {
		return nil, fmt.Errorf("field %s is not indexed", indexName)
	}

	// 1. 尝试从缓存获取
	if r.cache != nil {
		cacheKey := r.indexCacheKey(indexName, indexValue)
		if cached, err := r.cache.Get(ctx, cacheKey); err == nil && cached != nil {
			if ids, ok := cached.([]interface{}); ok {
				var entities []interface{}
				for _, id := range ids {
					if entity, err := r.FindByID(ctx, id); err == nil && entity != nil {
						entities = append(entities, entity)
					}
				}
				return entities, nil
			}
		}
	}

	// 2. 从数据库获取
	entities, err := r.db.FindByIndex(ctx, indexName, indexValue)
	if err != nil {
		return nil, err
	}

	// 3. 更新索引缓存
	if r.cache != nil {
		var ids []interface{}
		for _, entity := range entities {
			id, err := r.getIDValue(entity)
			if err != nil {
				continue
			}
			ids = append(ids, id)
		}

		cacheKey := r.indexCacheKey(indexName, indexValue)
		if err := r.cache.Set(ctx, cacheKey, ids); err != nil {
			return nil, err
		}
	}

	return entities, nil
}

// getIDValue 获取实体的ID值
func (r *genericRepository) getIDValue(entity interface{}) (interface{}, error) {
	if r.primaryKey == "" {
		return nil, ErrInvalidEntity
	}

	val := reflect.ValueOf(entity)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	field := val.FieldByName(r.primaryKey)
	if !field.IsValid() {
		return nil, ErrInvalidEntity
	}

	return field.Interface(), nil
}

// validateEntityType 验证实体类型
func (r *genericRepository) validateEntityType(entity interface{}) error {
	t := reflect.TypeOf(entity)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	if t != r.entityType {
		return fmt.Errorf("%w: expected %s, got %s",
			ErrInvalidEntity, r.entityType.Name(), t.Name())
	}
	return nil
}

// cacheKey 生成缓存键
func (r *genericRepository) cacheKey(id interface{}) string {
	return fmt.Sprintf("%s:%v", r.entityType.Name(), id)
}

// indexCacheKey 生成索引缓存键
func (r *genericRepository) indexCacheKey(indexName string, indexValue interface{}) string {
	return fmt.Sprintf("%s:index:%s:%v", r.entityType.Name(), indexName, indexValue)
}

// updateIndexes 更新索引缓存
func (r *genericRepository) updateIndexes(ctx context.Context, entity interface{}) error {
	if r.cache == nil {
		return nil
	}

	val := reflect.ValueOf(entity)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	for fieldName := range r.indexes {
		field := val.FieldByName(fieldName)
		if !field.IsValid() {
			continue
		}

		indexValue := field.Interface()
		cacheKey := r.indexCacheKey(fieldName, indexValue)

		// 获取当前索引关联的ID列表
		var ids []interface{}
		if cached, err := r.cache.Get(ctx, cacheKey); err == nil && cached != nil {
			if existingIds, ok := cached.([]interface{}); ok {
				ids = existingIds
			}
		}

		// 添加新ID
		id, err := r.getIDValue(entity)
		if err != nil {
			return err
		}

		// 检查ID是否已存在
		found := false
		for _, existingID := range ids {
			if existingID == id {
				found = true
				break
			}
		}

		if !found {
			ids = append(ids, id)
			if err := r.cache.Set(ctx, cacheKey, ids); err != nil {
				return err
			}
		}
	}

	return nil
}
